﻿using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class ClientSAEA {
    private readonly Socket socket_Client;
    private SocketAsyncEventArgs ServerSAEA_receive;
    private SocketAsyncEventArgs ServerSAEA_send;
    private readonly IPEndPoint ipEndPoint_Server;
    private int AsnyBufferLength = 64;

    public delegate void OnEventCompletedHanlder(string MassageArray);
    public event OnEventCompletedHanlder OnReceiveCompletedEvent;
    public event OnEventCompletedHanlder OnSendCompletedEvent;
    public event OnEventCompletedHanlder OnConnectedEvent;
    public event OnEventCompletedHanlder OnDisconnectEvent;
    public event OnEventCompletedHanlder OnNotConnectEvent;

    public ClientSAEA(string server_ip,int server_port)
    {
        socket_Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //生成服务器连接IP端口
        IPAddress ipAddress_server = IPAddress.Parse(server_ip);
        ipEndPoint_Server = new IPEndPoint(ipAddress_server,server_port);
        ServerSAEA_receive = new SocketAsyncEventArgs();
        ServerSAEA_receive.Completed += OnSAEACompleteEvent;
    }

    public void StartConnect()
    {
        //尝试连接服务器
        SocketAsyncEventArgs TempServerSAEA = new SocketAsyncEventArgs();
        TempServerSAEA.RemoteEndPoint = ipEndPoint_Server;
        TempServerSAEA.Completed += OnConnectServerComplete;
        bool willRaiseEvent =  socket_Client.ConnectAsync(TempServerSAEA);
        DebugHandler.GetInstance().DebugLog("开始异步连接结果"+ willRaiseEvent);
        if (!willRaiseEvent)
        {
            DebugHandler.GetInstance().DebugLog("同步连接成功");
            ConnectSuccessHandler(TempServerSAEA);
        }
    }

    /// <summary>
    /// 连接成功异步回调
    /// </summary>
    /// <param name="target"></param>
    /// <param name="saea"></param>
    public void OnConnectServerComplete(object target, SocketAsyncEventArgs saea)
    {
        DebugHandler.GetInstance().DebugLog("异步连接成功1");
        ConnectSuccessHandler(saea);
        DebugHandler.GetInstance().DebugLog("异步连接成功2");
    }

    /// <summary>
    /// 发送客户端消息给服务器
    /// </summary>
    /// <param name="model"></param>
    public void SendMessage(ClientMsgModel model)
    {
        byte[] sendBuffer = Encoding.Unicode.GetBytes(model.massage);
        ServerSAEA_send.SetBuffer(sendBuffer,0,sendBuffer.Length);
        Socket serverSocket = ServerSAEA_send.UserToken as Socket;
        bool willRaiseEvent = serverSocket.SendAsync(ServerSAEA_send);
        if (!willRaiseEvent)
        {
            OnSendComplete(ServerSAEA_send);
        }
    }

    /// <summary>
    /// 异步或同步连接成功后都会触发次函数
    /// </summary>
    /// <param name="saea"></param>
    public void ConnectSuccessHandler(SocketAsyncEventArgs saea)
    {
        //判断连接错误，返回
        if (saea.SocketError != SocketError.Success) return;
        DebugHandler.GetInstance().DebugLog("连接成功...");
        if (OnConnectedEvent!=null)
        {
            //todo 此处需要提前添加UI事件
            OnConnectedEvent("服务器连接成功");
        }
        //获取连接成功后的相关信息
        ServerSAEA_receive.RemoteEndPoint = saea.RemoteEndPoint;
        ServerSAEA_receive.UserToken = saea.ConnectSocket;

        ServerSAEA_send = new SocketAsyncEventArgs();
        ServerSAEA_send.RemoteEndPoint = saea.RemoteEndPoint;
        ServerSAEA_send.UserToken = saea.ConnectSocket;
        ServerSAEA_send.Completed += OnSAEACompleteEvent;
        //此处连接成功可以发送一个消息给服务器
        
        //使用专门处理接收的异步对象接收新消息
        bool willRaiseEvent = saea.ConnectSocket.ReceiveAsync(ServerSAEA_receive);
        if (!willRaiseEvent)
        {
            OnReceiveComplete(ServerSAEA_receive);
        }
    }

    /// <summary>
    /// 接收到新的操作时间回调
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="saea"></param>
    public void OnSAEACompleteEvent(object sender, SocketAsyncEventArgs saea)
    {
        //判断当前操作类型
        switch (saea.LastOperation)
        {
            case SocketAsyncOperation.Receive:
                //异步接收完成执行回调
                OnReceiveComplete(saea);
                break;
            case SocketAsyncOperation.Send:
                OnSendComplete(saea);
                break;
            default:
                Console.WriteLine("异常！该操作类型不是接收也不是发送");
                break;
        }
    }

    //异步发送成功回调
    private void OnSendComplete(SocketAsyncEventArgs saea)
    {
        DebugHandler.GetInstance().DebugLog("发送成功");
        if(OnSendCompletedEvent != null)
        OnSendCompletedEvent("消息发送成功");
    }

    //异步接收成功回调
    private void OnReceiveComplete(SocketAsyncEventArgs saea)
    {
        if(saea.SocketError != SocketError.Success) return;
        //获取有效消息长度
        int bufferLength = saea.BytesTransferred;
        if (bufferLength <= 0)
        {
            DebugHandler.GetInstance().DebugLog("与服务器断开连接");
            //关闭socket
            CloseClientSocket(saea);
        }
        else
        {
            byte[] receiveBuffer = saea.Buffer;
            byte[] buffer = new byte[bufferLength];
            Buffer.BlockCopy(receiveBuffer,0,buffer,0,bufferLength);
            //有效消息粘贴出来了，先开启下一次接收函数
            bool willRaiseEvent = socket_Client.ReceiveAsync(saea);
            if (!willRaiseEvent)
            {
                OnReceiveComplete(saea);
            }

            if (OnReceiveCompletedEvent != null)
            {
                OnReceiveCompletedEvent("接收成功，处理新的消息");
            }
        }
    }

    /// <summary>
    /// 关闭服务器异步对象
    /// </summary>
    /// <param name="saea"></param>
    public void CloseClientSocket(SocketAsyncEventArgs saea)
    {
        //关闭服务器socket
        try
        {
            saea.ConnectSocket.Shutdown(SocketShutdown.Send);   
        }
        catch (Exception) {}
        saea.ConnectSocket.Close();
    }

}
